package nancal.mp.util


import nbcp.base.comm.JsonMap
import nbcp.base.extend.*
import nbcp.base.utils.RecursionUtil
import nbcp.base.utils.ReflectUtil
import nbcp.base.utils.WbsNoKeyTouchEnum


fun <T : MutableMap<String, Any?>> T.disableIstio(): T {
    var map = ReflectUtil.getValueByWbsPath(
        this,
        "spec.template.metadata.annotations",
        touchType = WbsNoKeyTouchEnum.Fill
    ) as LinkedHashMap<String, Any?>?

    if (map == null) {
        return this;
    }

    map.set("sidecar.istio.io/inject", "false")
    return this;
}

fun <T : MutableMap<String, Any?>> T.setNamespace(namespace: String): T {
    //添加 metadata
    var metadataKey = "metadata"
    if (this.contains(metadataKey) == false) {
        this.put(metadataKey, mutableMapOf<String, Any>())
    }

    var metadata = this.get(metadataKey) as MutableMap<String, Any?>;
    if (metadata == null) {
        throw RuntimeException("找不到 metadata")
    }

    metadata.put("namespace", namespace);
    return this;
}


fun <T : MutableMap<String, Any?>> T.setName(name: String): T {
    //添加 metadata
    var metadataKey = "metadata"
    if (this.contains(metadataKey) == false) {
        this.put(metadataKey, mutableMapOf<String, Any>())
    }

    var metadata = this.get(metadataKey) as MutableMap<String, Any?>;
    if (metadata == null) {
        throw RuntimeException("找不到 metadata")
    }

    metadata.put("name", name);
    return this;
}

fun <T : MutableMap<String, Any?>> T.setReplicasAtLeast1(): T {
    //添加 metadata
    var replicate = this.getValueByWbsPath("spec.replicas").AsInt()
    if (replicate > 0) {
        return this;
    }

    var spec = ReflectUtil.getValueByWbsPath(
        this,
        "spec",
        touchType = WbsNoKeyTouchEnum.Fill
    ) as MutableMap<String, Any?>

    spec.set("replicas", 1);
    return this;
}

/**
 * 设置第一个有 env 参数的参数值.
 */
fun <T : MutableMap<String, Any?>> T.setEnvParameter(key: String, value: String): T {
    if (value.isEmpty()) return this;

    var firstEnv =
        (this.getValueByWbsPath("spec.template.spec.containers[].env") as List<MutableList<MutableMap<String, Any?>>>?)?.firstOrNull();
    if (firstEnv != null) {
        var firstItem = firstEnv.firstOrNull { it.get("name").AsString() == key }
        if (firstItem != null) {
            firstItem.set("value", value)
        } else {
            firstEnv.add(mutableMapOf("name" to key, "value" to value))
        }
//        firstEnv.forEach { envMap ->
//
//            if (envMap.getStringValue("name") == key) {
//                envMap.set("value", value)
//            }
//        }
    }

    return this;
}


fun <T : MutableMap<String, Any?>> T.setEnvProfile(profile: String): T {
    if (profile.isEmpty()) return this;

    var envs =
        (this.getValueByWbsPath("spec.template.spec.containers[].env") as List<List<MutableMap<String, Any?>>>?)?.firstOrNull();
    if (envs != null) {
        envs.forEach {
            if (it.get("name").AsString() == "PROFILE") {

                var v2 = it.get("value").AsString().split(",")
                    .map {
                        if (it.IsInItems("dev", "test", "main")) {
                            return@map profile
                        }

                        return@map it;
                    }
                    .toSet()
                    .filter { it.HasValue }
                    .joinToString(",")

                it.set("value", v2)
            }

        }
    }

    return this;
}


fun <T : MutableMap<String, Any?>> T.tidyK8sYaml(warningNamespace: Boolean = false): T {
    var deploymentMap = this;
    deploymentMap.remove("status")

    if (warningNamespace) {
        deploymentMap.setNamespace("~~需要设置名称空间~~")
    }

    remove_metadata_items(deploymentMap)


    var spec = deploymentMap.get("spec") as MutableMap<String, Any?>?
    if (spec == null) {
        remove_empty_map(this);
        return this;
    }

    tidyForService(spec);

    spec.remove("strategy")


    var template = spec.get("template") as MutableMap<String, Any?>?
    if (template == null) {
        remove_empty_map(this);
        return this;
    }

    remove_metadata_items(template);

    var spec2 = template.get("spec") as MutableMap<String, Any?>?
    if (spec2 == null) {
        remove_empty_map(this);
        return this;
    }
    proc_spec_template_spec(spec2)

    remove_empty_map(this);
    return this;
}


fun <T : MutableMap<String, Any?>> T.setPrivileged(): T {
    var deploymentMap = this;

    var spec = deploymentMap.get("spec") as MutableMap<String, Any?>?
    if (spec == null) {
        return this;
    }

    var template = spec.get("template") as MutableMap<String, Any?>?
    if (template == null) {
        return this;
    }

    var spec2 = template.get("spec") as MutableMap<String, Any?>?
    if (spec2 == null) {
        return this;
    }

    var containers = spec2.get("containers") as List<MutableMap<String, Any?>>?

    containers?.forEach {
        var securityContext = it.get("securityContext") as MutableMap<String, Any?>?
        if (securityContext == null) {
            securityContext = JsonMap();
            it.put("securityContext", securityContext)
        }

        securityContext.put("allowPrivilegeEscalation", true);
        securityContext.put("privileged", true);
    }
    return this;
}

private fun remove_empty_map(map: MutableMap<String, Any?>) {
    for (key in map.keys) {
        var value = map.get(key);
        if (value == null) {
            map.remove(key);
            continue;
        }

        if (value is MutableMap<*, *>) {
            if (value.any() == false) {
                map.set(key, null);
                continue;
            }
            remove_empty_map(value as MutableMap<String, Any?>);
        }
    }
}

private fun proc_spec_template_spec(spec2: MutableMap<String, Any?>) {

    var containers = spec2.get("containers") as List<MutableMap<String, Any?>>?

    containers?.forEach {
        it.remove("resources")

        RecursionUtil.recursionJson(it, { it ->
            var map = it as MutableMap<String, Any?>

            proc_port(map, "port")

            return@recursionJson true
        })
    }

    var initContainers = spec2.get("initContainers") as List<MutableMap<String, Any?>>?
    initContainers?.forEach {
        it.remove("resources")
    }
}

private fun remove_metadata_items(map: MutableMap<String, Any?>) {

    var metadata = map.get("metadata") as MutableMap<String, Any?>?
    if (metadata == null) {
        return;
    }

    metadata.remove("creationTimestamp")
    metadata.remove("generation")
    metadata.remove("resourceVersion")
    metadata.remove("selfLink")
    metadata.remove("uid")
    metadata.remove("managedFields")

    val annotations = metadata.get("annotations") as MutableMap<String, Any?>?
    if (annotations != null) {
        annotations.remove("deployment.kubernetes.io/revision")
        annotations.remove("kubectl.kubernetes.io/last-applied-configuration")
        annotations.remove("kubectl.kubernetes.io/restartedAt") //它更深一点

//        if( annotations.isEmpty()){
//            metadata.remove("annotations")
//        }
    }
}


private fun tidyForService(spec: MutableMap<String, Any?>) {
    spec.remove("clusterIP") //Service
    spec.remove("clusterIPs") //Service

    var ports = spec.get("ports") as List<MutableMap<String, Any?>>?
    ports?.forEach { map ->
        proc_port(map, "port")
        proc_port(map, "targetPort")
        proc_port(map, "nodePort")
        proc_port(map, "containerPort")
    }
}

private fun proc_port(map: MutableMap<String, Any?>, key: String) {
    var port = map.get(key)
    if (port != null) {
        if (port is Map<*, *>) {
            if (port.get("isInt").AsBoolean()) {
                map.set(key, port.get("intValue"))
            } else {
                map.set(key, port.get("strValue"))
            }
        }
    }
}
